﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Web.Hosting;

namespace Lava.Web
{
    public class ScriptBuilder
    {
        private static readonly string _defaultReplaceFormat = @"{{{{" + "{0}" + @"}}}}";
        private readonly string _replaceFormat;
        private readonly string _scriptVirtualPath;
        private readonly string _devScriptVirtualPath;
        private readonly IEnumerable<string> _dependencies;

        public ScriptBuilder(string scriptVirtualPath, string devScriptVirtualPath, IEnumerable<string> dependencies, string replaceFormat = null)
        {
            _scriptVirtualPath = scriptVirtualPath;
            _devScriptVirtualPath = devScriptVirtualPath;
            _dependencies = dependencies;
            _replaceFormat = replaceFormat ?? _defaultReplaceFormat;
        }

        public static void BuildAndWatch(string scriptVirtualPath, string devScriptVirtualPath, IEnumerable<string> dependencies)
        {
            var scriptBuilder = new ScriptBuilder(scriptVirtualPath, devScriptVirtualPath, dependencies);
            scriptBuilder.Build();
            scriptBuilder.Watch();
        }

        public void Watch()
        {
            FileWatcher.OnChange(_scriptVirtualPath, new List<string>(_dependencies) { _devScriptVirtualPath }, (fileName) => Build());
        }

        public void Build()
        {
            string devScriptPath = HostingEnvironment.MapPath(_devScriptVirtualPath);
            string scriptPath = HostingEnvironment.MapPath(_scriptVirtualPath);
            var script = new StringBuilder();

            if (devScriptPath == null) {
                throw new FileNotFoundException("devScriptPath");
            }
            if (scriptPath == null) {
                throw new FileNotFoundException("scriptPath");
            }

            try
            {
                using (var reader = new StreamReader(devScriptPath))
                {
                    script.Append(reader.ReadToEnd());
                }

                foreach (var dependency in _dependencies)
                {
                    string dependencyPath = HostingEnvironment.MapPath(dependency);
                    if (dependencyPath == null)
                    {
                        throw new FileNotFoundException("dependencyPath");
                    }
                    using (var reader = new StreamReader(dependencyPath))
                    {
                        script = script.Replace(string.Format(_replaceFormat, Path.GetFileName(dependency)), reader.ReadToEnd());
                    }
                }

                using (var writer = new StreamWriter(scriptPath))
                {
                    writer.Write(script.ToString());
                }
            }
            catch (Exception ex)
            {
                if (!ex.IsFileLockedException())
                {
                    throw;
                }
            }
        }
    }
}